<?php

namespace Modules\Wechat\Controllers;

use Base\Exception\Controller as Exception;
use Modules\Wechat\Model\Data\Message\Exchange as MsgExchange;
use S\Response;
use S\WeChat;

/**
 * 接收消息的控制器抽象类
 *
 * 上层业务所有接收微信消息的控制器都必须继承此类.
 * 实现此类中的抽象方法之后,微信发来的消息会被传递至上层应用的业务逻辑层(Service)进行处理.具体
 * 规则见\Modules\Wechat\Model\Util\Dispatcher.
 *
 * @package Modules\Wechat\Controllers
 */
abstract class MessagePortal extends AccountDifferentiating
{
    const MESSAGE_HANDLER = '\\Modules\\Wechat\\Model\\Service\\Message\\Dispatcher::dispatch';

    /** @var \EasyWeChat\Foundation\Application $wechat_app */
    protected $wechat_app = null;

    protected function beforeParams()
    {
        Response::setFormatter(Response::FORMAT_PLAIN);
    }

    protected function params()
    {
        return [];
    }

    protected function beforeAction()
    {
        $this->setMessageHandler(static::MESSAGE_HANDLER);
    }

    /**
     * @param \EasyWeChat\Message\AbstractMessage $message_request
     * @param \EasyWeChat\Message\AbstractMessage $message_response
     *
     * @throws \Base\Exception\Controller
     */
    protected function afterAction($message_request, $message_response)
    {
        try {
            $Exchange = new MsgExchange;
            $Exchange->addByMessageRequest($message_request);
            $Exchange->addByMessageResponse($message_response);
        } catch (\Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }
    }

    /**
     * 设置消息处理器
     *
     * @param callable|string $handler 消息处理器:和call_user_func()函数的第一个参数格式相同
     *
     * @return \EasyWeChat\Server\Guard
     * @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
     */
    protected function setMessageHandler($handler = self::MESSAGE_HANDLER)
    {
        return Wechat::app($this->getWechatAccountWhichTriggersCurrentController())
            ->server->setMessageHandler($handler);
    }

    /**
     * 响应微信请求
     *
     * @throws \EasyWeChat\Core\Exceptions\InvalidArgumentException
     */
    protected function action()
    {
        $account        = $this->getWechatAccountWhichTriggersCurrentController();
        $Server         = Wechat::app($account)->server;
        $this->response = $Server->serve()->getContent();
        if (empty(\S\Request::get('echostr'))) {
            $this->afterAction($Server->getMessageRequest(), $Server->getMessageResponse());
        }
    }

}